/**
 *******************************************************************************************************************************************
 * @file        main.c
 * @brief       主程序

 *******************************************************************************************************************************************
 */
#include <stdbool.h>
#include <stdint.h>
#include <string.h>

#include "SWM341.h"
#include "version.h"
#include "bsp_init.h"
#include "variable_middle.h"
#include "user_app.h"
#include "ugui.h"

static void jump_to_app(const uint32_t addr);
static void reset_mcu(void);
static void check_app(const uint32_t addr);
/***********************************************************************************************************
 * Private Function
 *******************************************************************************************************************/
//**************************************
//#include "userboot.h"

/*******************************************************************************************************************************************
 * Private Define
 *******************************************************************************************************************************************/
#define WDT_ENABLE              0 /**< 看门狗(1-使能, 0-失能) */
#define SLEEP_ENABLE            0 /**< 休眠演示(1-使能, 0-失能) */
#if (SLEEP_ENABLE != 0)
#include "power_manager.h"
/** 超过指定时长无触摸交互则进入低功耗睡眠 */
#define SLEEP_TIME_MS           (30 * 1000)
#endif

/*******************************************************************************************************************************************
 * Public Variable
 *******************************************************************************************************************************************/
/** 手指触摸释放时长 / ms, 反映屏幕多长时间未被点击, 一旦有新的点击触发, 其值立即清零 */
volatile uint32_t Systick_Ms_TP = 0;
volatile uint8_t one_ms_flag, led_flag;
volatile uint16_t one_ms_time;

/*******************************************************************************************************************************************
 * Private Prototype
 *******************************************************************************************************************************************/
static void gui_init(void);
static void user_app(void);
static void app_task_handler(void);


/*******************************************************************************************************************************************
 * Public Function
 *******************************************************************************************************************************************/
/**
 * @brief   C_Main
 */
int main(void)
{
    /* 在调测阶段(版本 Release 时可注释), 预防程序跑飞后, 上电无法读取 MCU 内核, 也可用作等待个别硬件模块上电稳定 */
    for (uint32_t i = 0; i < 66666 * 88; ++i) __NOP();
    bsp_init();
    if (SYS->RSTSR & SYS_RSTSR_POR_Msk) // 1 出现过 POR 复位, 写1清零
    {
        SYS->RSTSR |= (1 << SYS_RSTSR_POR_Pos);
    }
    if (SYS->RSTSR & SYS_RSTSR_WDT_Msk) // 1 出现过 WDT 复位, 写1清零
    {
        SYS->RSTSR |= (1 << SYS_RSTSR_WDT_Pos);
    }
    //检测启动引导标志位
    check_app(Firmware_Addr);
    //检测烧写启动标志位
    config_read();
  
   
    if (s.wait_load)
    {
        uart_debug_init(YMOD_BPS);
        s.down_loading = 1;
        eot_num = 0;
        wait_out_time = 60000;
    }
    else
    {
        uart_debug_init(9600);
        s.down_loading = 0;
        eot_num = 0;
        wait_out_time = 300;
    }
    receive_count = 0;
    s.erase_ok = 0;
    while (wait_out_time)
    {
        app_task_handler();
    }
    if (s.app_ok)
    {
        /* 跳转到APP前需要将 UserBoot 使用的外设关掉（复位）*/
        __disable_irq();
        #if 1 /* 由于 Systick 属于内核附带的外设, 如在 Boot 中有使用开启, 则需要单独使用以下语句关闭, 否则跳转 APP 将会失败 */
        /* Disable SysTick IRQ and SysTick Timer */
        SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk);
        #endif
        /* 个别外设不能重复初始化, 故需要在跳转前先复位,
         * 但对于 GPIO 而言, 由于复位后为浮空状态, 对于需要保持 IO 输出电平的场景(eg : IO控制外部器件供电), 跳转时无需复位 GPIO
         */
        SYS->PRSTEN = 0x55;
        SYS->PRSTR0 = 0xFFFFFFFF & (~SYS_PRSTR0_ANAC_Msk); /* 始终不允许复位 ANAC 模拟控制单元 */
        SYS->PRSTR1 = 0xFFFFFFFF;
        for (int i = 0; i < CyclesPerUs; i++)
            __NOP();
        SYS->PRSTR0 = 0;
        SYS->PRSTR1 = 0;
        SYS->PRSTEN = 0;
        NVIC->ICER[0] = 0xFFFFFFFF;
        NVIC->ICER[1] = 0xFFFFFFFF;
        NVIC->ICER[2] = 0xFFFFFFFF;
        jump_to_app(Firmware_Addr);
    }
    else
    {
       
        uart_debug_init(9600);
        s.down_loading = 0;
        eot_num = 0;
        wait_out_time = 300;
    }
    Buzzer_cotrl(500);
    gui_init();
    for (;;)
    {
        app_task_handler();
    }
    return 0;
}

/**
 * @brief   Systick ISR Callback
 * @note    1 ms 被调用 1 次, 执行时长不应超过计时周期
 */
void isr_systick(void)
{
    systick_inc_tick();
    ++Systick_Ms_TP;
    one_ms_time++ ;
    if (one_ms_time > 200)
    {
        one_ms_time = 0;
        one_ms_flag = 1;
    }
    if (wait_out_time)
    {
        wait_out_time--;
    }
		//********************
		
    //********************************************
    if (s.down_loading)
    {
        if (s.send_run_flag == 0)
        {
            send_run_time++;
            if (send_run_time > SET_GET_PER)
            {
                send_run_time = 0;
                s.send_run_flag = 1;
							  hank_out_time++;
								if(hank_out_time>100)
								{
									reset_mcu();
								}
            }
        }
    }
    //*********************************************
    //*****************************************
    if (s.buzzer)
    {
        buzzer_time++;
        if (buzzer_time > buzzer_set_time)
        {
            buzzer_time = 0;
            BUZZER_OFF();
            s.buzzer = 0;
        }
    }
}


/**
 * @brief   LVGL Core/Port Init
 */
//#include "midlle_v.h"

static void app_task_handler(void)
{
    UART_Receive();   //数据解析进程
    UART_Send();    //数据发送进程
    //*******************************************
    if (one_ms_flag)
    {
        one_ms_flag = 0;
        if (led_flag)
        {
            led_flag = 0;
            LED_ON();
        }
        else
        {
            led_flag = 1;
            LED_OFF();
        }
    }
    //**************************************
    if (s.touch_buzzer)
    {
        s.touch_buzzer = 0;
        Buzzer_cotrl(200);
    }
    //********************************
}
static void gui_init(void)
{
    //    lv_init();
    //    lv_port_disp_init();
    //    lv_port_indev_init();
    // lv_port_fs_init();
}

#if (WDT_ENABLE != 0)
/**
 * @brief   喂狗任务
 * @param   t  : 任务句柄
 * @retval  /
 * @note    两次喂狗之间 <必须> 至少 间隔 2 个WDT时钟周期(即 60 us)
 */
static void wdt_feed_cb(lv_task_t *t)
{
    WDT->FEED = 0x55;//WDT_Feed(WDT);
}
#endif




/**
 * @brief   Go to User App Execute
 */
static void user_app(void)
{
    //*********************************************************
    #if(BLUE_ENABLE)
    send_BLE_Reset_order();
    s.get_name_flag = 1;
    s.mac_flag = 1;
    #endif
    uart_debug_init(9600);
    s.down_loading = 0;
    eot_num = 0;
}


/**
 * @brief   跳转至 APP 加载地址运行
 * @param   addr : APP 加载地址
 * @retval  /
 * @note    通过判断栈定地址值来辨别传入地址上的应用程序是否有效
 */
static void jump_to_app(const uint32_t addr)
{
    /* 启动先跳转到系统 BootLoader, 首地址是 MSP, 地址 + 4 是复位中断服务程序地址 */
    uint32_t sp = *((volatile uint32_t *)(addr));
    uint32_t pc = *((volatile uint32_t *)(addr + 4));
    typedef void (*Func_void_void)(void);
    Func_void_void ResetHandler = (Func_void_void)(0x00);
    /*  通过判断栈定地址值是否在 0x2000 0000 - 0x2001 0000 之间 ( SWM341 RAM Max : 0x10000 <64KB> ) 来判断应用程序是否已经下载到指定地址.
     *  因为中断向量表里第一个放的就是栈顶地址的值, 如果该值不在 RAM 区间地址内, 即使这是固件也是不合法的.
     */
    if ((sp & 0x2FFE0000) == 0x20000000 && (sp & 0x0001FFFF) < 0x00010000)
    {
        ResetHandler = (Func_void_void)pc;
        SCB->VTOR = addr; /* 设置中断向量表地址 */
        __set_MSP(sp); /* 设置主堆栈指针 */
        //__set_CONTROL(0); /* 注意使用 RTOS 时，设置为特权级模式，使用 MSP, 而不是 PSP */
    }
    else /* 该地址上没有可正常运行的固件, 传参异常抛出 */
    {
        // UB_LOG("No firmware for APP load address 0x[%x] \r\n", addr);
    }
    ResetHandler();
    for (;;)
    {
    }
}
static void check_app(const uint32_t addr)
{
    /* 启动先跳转到系统 BootLoader, 首地址是 MSP, 地址 + 4 是复位中断服务程序地址 */
    uint32_t sp = *((volatile uint32_t *)(addr));
    uint32_t pc = *((volatile uint32_t *)(addr + 4));
    typedef void (*Func_void_void)(void);
    Func_void_void ResetHandler = (Func_void_void)(0x00);
    /*  通过判断栈定地址值是否在 0x2000 0000 - 0x2001 0000 之间 ( SWM341 RAM Max : 0x10000 <64KB> ) 来判断应用程序是否已经下载到指定地址.
     *  因为中断向量表里第一个放的就是栈顶地址的值, 如果该值不在 RAM 区间地址内, 即使这是固件也是不合法的.
     */
    uint32_t check_data = *((volatile uint32_t *)(Check_data_addr));
    // if ((sp & 0x2FFE0000) == 0x20000000 && (sp & 0x0001FFFF) < 0x00010000 )
    if ((sp & 0x2FFE0000) == 0x20000000 && (sp & 0x0001FFFF) < 0x00010000 && (check_data == CHECK_FLAG))
    {
        s.app_ok = 1;
    }
    else /* 该地址上没有可正常运行的固件, 传参异常抛出 */
    {
        s.app_ok = 0;
    }
}
/*******************************************************************************************************************************************
 * Private Function
 *******************************************************************************************************************************************/
/**
 * @brief   重启 MCU
 * @param   /
 * @retval  /
 * @note    相比于 NVIC_SystemReset() , 看门狗从硬件层面保证可靠性, 可确保寄存器的复位值均恢复默认.
 */
static void reset_mcu(void)
{
    WDT_Init(WDT, 0, 1);
    WDT_Start(WDT);
    for (;;)
        ;
}